package cl.foursoft.eee.util.CalculosMatematicos;

import java.util.ArrayList;
import java.util.List;

import cl.foursoft.eee.dao.transferObject.AlternativaDeInversionTO;
import cl.foursoft.eee.dao.transferObject.EdificioTO;
import cl.foursoft.eee.dao.transferObject.ParametrosEdificioTO;
import cl.foursoft.eee.dao.transferObject.RequerimientoEnergeticoTO;
import cl.foursoft.eee.dao.transferObject.SeccionTO;
import cl.foursoft.eee.util.EnumParametros;
import cl.foursoft.eee.util.EnumSecciones;

/**
 * @author IgnacioGuajardo
 *
 */
public class RequerimientoEnergeticoUtil {
	
	private EdificioTO edificioParaCalculo;
	private List<ParametrosEdificioTO> parametrosEdificio;
	private List<SeccionTO> seccionesEdificio; //Sustituir pot EnvolventeTO
	private RequerimientoEnergeticoTO requerimiento = null;
	private float areaTotalSecciones;
	
	private float perdidaPorTransmisionTotal;
	private float perdidaPorVentilacion;
	
	/*
	 * Constructores 
	 */	
	public  RequerimientoEnergeticoUtil(EdificioTO edificio){
		this.edificioParaCalculo = edificio;
		this.areaTotalSecciones = 0;
		parametrosEdificio = this.edificioParaCalculo.getArrCollParametrosEdificio();
		seccionesEdificio  = this.edificioParaCalculo.getArrCollSecciones();
	}
	public RequerimientoEnergeticoUtil(AlternativaDeInversionTO alternativa,EdificioTO edificio){
		
		this.edificioParaCalculo = edificio;
		seccionesEdificio = alternativa.getEnvolventeNueva().obtenerListaSecciones(); //Pasar los 4 objetos secciones a un List<SeccionTO>
		if(edificio!=null)
			parametrosEdificio = edificio.getArrCollParametrosEdificio();
		else
			parametrosEdificio = new ArrayList<ParametrosEdificioTO>(); 
		
	}
	public  RequerimientoEnergeticoUtil(){
		this.edificioParaCalculo = new EdificioTO();	
		this.areaTotalSecciones = 0;
	}
	
	/*
	 * Función que realiza el cálculo del Requerimiento Energético.
	 */
	public RequerimientoEnergeticoTO calcularRequerimientoEnergetico(){
		requerimiento = new RequerimientoEnergeticoTO();
		SeccionTO ventanas = null;
		
		//Obtener las Ventanas.
		for(SeccionTO s : seccionesEdificio){
			if(s.getNombreTipo().equals(EnumSecciones.SECCION_VENTANAS))
				ventanas = s;
		}

		//1. Perdidas por Transmision Total. Están en cada seccion los calculos parciales
		requerimiento.setPerdidasPorTransmision(PerdidasPorTransmision());
		
		//2. Perdidas por Ventilación Total. se calcul para el edificio completo
		requerimiento.setPerdidasPorVentilacion(PerdidasPorVentilacion());
		
		//3. Gancia Solar por sol de Verano
		requerimiento.setGananciaTermicaSolVerano(GananciaTermicaPorSolVerano(ventanas));
		
		//4 Ganancia Solar por sol de Invierno
		requerimiento.setGananciaTermicaSolInvierno(GananciaTermicaPorSolInvierno(ventanas));

		//5 Ganancia termica sol
		requerimiento.setGananciaTermicaSol(requerimiento.getGananciaTermicaSolInvierno() + requerimiento.getGananciaTermicaSolVerano());
		
		//6 Ganancia Interna
		requerimiento.setGananciaInterna(GananciaInterna());
		
		//7 Requerimiento Frio
		requerimiento.setRequerimientoFrioTotal(calcularRequerimientoTotalFrio());
		//8 Requerimiento Calor
		requerimiento.setRequerimientoCalorTotal(calcularRequerimientoTotalCalor());
		//9 Requerimiento Total
		requerimiento.setRequerimientoEnergeticoTotal(RequerimientoEnergeticoTotal());
		
		return requerimiento;
	}
	
	/* 1 / 8
	 * PERDIDAS POR TRANSMISION (Valor Total).
	 * Descripción	: Se calcula para cada sección.
	 * Formula		: (1 + PVT) * ∑Ht.
	 * Unidad		: -
	 */
	private float PerdidasPorTransmision(){
		float resp = 0;
		areaTotalSecciones = areaTotalSecciones();
		perdidaPorTransmisionTotal = 0;
		
		for (SeccionTO s : seccionesEdificio) {
			perdidaPorTransmisionTotal+= PerdidasPorTransmisionPorSeccion(s);
		}
 
		
		resp = ( (perdidaPorTransmisionTotal)*obtenerParametro(EnumParametros.PVT) / 100 ) + perdidaPorTransmisionTotal ; 
		
		
		return resp; 
		
	}
	
	//-----------------------------------------------------------------
	/* 2 / 8
	 * Cálculo		: PERDIDAS POR TRANSMISION [PARA UNA SECCIÓN]
	 * Descripción	: Se calcula para cada sección.
	 * Formula		: Ai*U*Fx + (PVP+A).
	 * Unidad		: -
	 */
	private float PerdidasPorTransmisionPorSeccion(SeccionTO seccion){
		float resp = 0;
		float factorCorreccion = 0;
		float variacionParcial =  obtenerParametro(EnumParametros.PVP) / 100;
		
		if(seccion.getNombreTipo().equals(EnumSecciones.SECCION_AREA_SUPERIOR) || seccion.getNombreTipo().equals(EnumSecciones.SECCION_MUROS) ||  seccion.getNombreTipo().equals(EnumSecciones.SECCION_PUERTAS) ||  seccion.getNombreTipo().equals(EnumSecciones.SECCION_VENTANAS) ){
			
			 factorCorreccion = obtenerParametro(EnumParametros.FE);
				resp =(seccion.getArea()*seccion.getTransmitanciaTermica()*factorCorreccion)+(variacionParcial * areaTotalSecciones);

		}
		
		if(seccion.getNombreTipo().equals(EnumSecciones.SECCION_AREA_BASE)){
			List<SeccionTO> base = seccion.getSeccionesHijo();
			for(SeccionTO s : base){
				resp += PerdidasPorTransmisionPorSeccion(s);
			}
		}		 
		
		if(seccion.getNombreTipo().equals(EnumSecciones.SECCION_PISO)){
			
			factorCorreccion = obtenerParametro(EnumParametros.FG1);
			resp = (seccion.getArea()*seccion.getTransmitanciaTermica()*factorCorreccion) +(variacionParcial* areaTotalSecciones);
		}
		if(seccion.getNombreTipo().equals(EnumSecciones.SECCION_ESCALERA)){
			
			factorCorreccion = obtenerParametro(EnumParametros.FG2);
			resp = (seccion.getArea()*seccion.getTransmitanciaTermica()*factorCorreccion)+(variacionParcial * areaTotalSecciones);
		}
		
		
		
		//seccion.setPerdidaPorTransmision(perdidaPorTransmision);
		 return resp;
	}
	
	//-----------------------------------------------------------------
	/*  3 / 8
	 * Cálculo		: PERDIDAS POR VENTILACION (Se calcula para el edificio).
	 * Descripción	: Se calcula para el edificio.
	 * Fórmula		: 𝐹𝑝𝑣 ∗ 𝑁 ∗ 𝑉
	 * Unidad		: w/k.
	 */
	private float PerdidasPorVentilacion(){
		
		float fpv 	= obtenerParametro(EnumParametros.FPV);
		float n 	= obtenerParametro(EnumParametros.NCA);//Nuemro de cambios de aireç
		float v 	= edificioParaCalculo.getVolumenDeAire(); 
		
		
		perdidaPorVentilacion = fpv * n * v;
		
		return perdidaPorVentilacion;
	}
	
	//-----------------------------------------------------------------
	/* 4 / 8 
	 * Cálculo		: GANANCIA TERMICA POR SOL DE VERANO.
	 * Descripción	: Se Calcula para las ventanas segun la orientación 
	 * Fórmula		: ∑ Qsv.
	 * Unidad		: KWh/a.
	 */
	private float GananciaTermicaPorSolVerano(SeccionTO ventana){
		float gananciaSolVeranoTotal = 0;
		
		for(SeccionTO s : ventana.getSeccionesHijo()){
			gananciaSolVeranoTotal+= GananciaTermicaPorSolVeranoPorVentana(s);
		}
		return gananciaSolVeranoTotal;
	}

	//-----------------------------------------------------------------
	/* 5 / 8
	 * Cálculo		: GANANCIA TERMICA POR SOL DE VERANO. CALCULO PARA CADA CONJUNTO DE VENTANAS POR UBICACION
	 * Descripción	: Cálculo para cada ventana, según su orientación geográfica.
	 * Fórmula		: ∑(𝐹𝑔𝑠𝑣∙𝐴𝑣𝑖∙𝑔∙ 𝐹𝑠∙𝐹𝑚∙𝐹c)
	 * Unidad		: KWh/a.
	 */
	private float GananciaTermicaPorSolVeranoPorVentana(SeccionTO ventana){
		float gananciaSolVeranoParcial = 0;
		float factorGanancia = 0;
		float constante = obtenerParametro(EnumParametros.G)*obtenerParametro(EnumParametros.FS)*obtenerParametro(EnumParametros.FM)*obtenerParametro(EnumParametros.FC);
		
		
		if(ventana.getNombreTipo().equals(EnumSecciones.VENTANAS_NORTE)){
			factorGanancia = obtenerParametro(EnumParametros.FGSV1);
		}
		else if(ventana.getNombreTipo().equals(EnumSecciones.VENTANAS_NONP)){
			factorGanancia = obtenerParametro(EnumParametros.FGSV2);			
		}
		else if(ventana.getNombreTipo().equals(EnumSecciones.VENTANAS_PONIENTES)){
			factorGanancia = obtenerParametro(EnumParametros.FGSV3);			
		}
		else if(ventana.getNombreTipo().equals(EnumSecciones.VENTANAS_SUR)){
			factorGanancia = obtenerParametro(EnumParametros.FGSV4);			
		}
		else if(ventana.getNombreTipo().equals(EnumSecciones.VENTANAS_SOSP)){
			factorGanancia = obtenerParametro(EnumParametros.FGSV5);			
		}
		else if(ventana.getNombreTipo().equals(EnumSecciones.VENTANAS_ORIENTE)){
			factorGanancia = obtenerParametro(EnumParametros.FGSV6);			
		}
		
		gananciaSolVeranoParcial = factorGanancia*ventana.getArea()*constante;
		return gananciaSolVeranoParcial;
	}

	//-----------------------------------------------------------------
	/* 6 / 8
	 * Cálculo		: GANANCIA TERMICA POR SOL DE INVIERNO.
	 * Descripción	: Se Calcula para las ventanas segun la orientación 
	 * Fórmula		: ∑ Qsvi
	 * Unidad		: KWh/a.
	 */
	private float GananciaTermicaPorSolInvierno(SeccionTO ventana){
		
		float gananciaSolInviernoTotal = 0;
		
		for(SeccionTO s : ventana.getSeccionesHijo()){
			gananciaSolInviernoTotal+= GananciaTermicaPorSolInviernoPorVentana(s);
		}
		return gananciaSolInviernoTotal;
		
		
	}

	//-----------------------------------------------------------------
	/* 7 / 8
	 * Cálculo		: GANANCIA TERMICA POR SOL DE INVIERNO. CALCULO PARA CADA CONJUNTO DE VENTANAS POR UBICACION
	 * Descripción	: Cálculo para cada ventana, según su orientación geográfica.
	 * Fórmula		: ∑(𝐹𝑔𝑠i∙𝐴𝑣𝑖∙𝑔∙ 𝐹𝑠∙𝐹𝑚∙𝐹c)
	 * Unidad		: KWh/a.
	 */
	private float GananciaTermicaPorSolInviernoPorVentana(SeccionTO ventana){
		float gananciaSolInviernoParcial = 0;
		float factorGanancia = 0;
		float constante = obtenerParametro(EnumParametros.G)*obtenerParametro(EnumParametros.FS)*obtenerParametro(EnumParametros.FM)*obtenerParametro(EnumParametros.FC);

		
		if(ventana.getNombreTipo().equals(EnumSecciones.VENTANAS_NORTE)){
			factorGanancia = obtenerParametro(EnumParametros.FGSI1);
		}
		else if(ventana.getNombreTipo().equals(EnumSecciones.VENTANAS_NONP)){
			factorGanancia = obtenerParametro(EnumParametros.FGSI2);			
		}
		else if(ventana.getNombreTipo().equals(EnumSecciones.VENTANAS_PONIENTES)){
			factorGanancia = obtenerParametro(EnumParametros.FGSI3);			
		}
		else if(ventana.getNombreTipo().equals(EnumSecciones.VENTANAS_SUR)){
			factorGanancia = obtenerParametro(EnumParametros.FGSI4);			
		}
		else if(ventana.getNombreTipo().equals(EnumSecciones.VENTANAS_SOSP)){
			factorGanancia = obtenerParametro(EnumParametros.FGSI5);			
		}
		else if(ventana.getNombreTipo().equals(EnumSecciones.VENTANAS_ORIENTE)){
			factorGanancia = obtenerParametro(EnumParametros.FGSI6);			
		}
		
		gananciaSolInviernoParcial = factorGanancia*ventana.getArea()*constante;
		return gananciaSolInviernoParcial;
	}
	
	//-----------------------------------------------------------------
	/* 8 / 8
	 * Cálculo		: GANANCIA INTERNA
	 * Descripción	: Cálculo para el Edificio Completo.
	 * Fórmula		: 𝑞𝑖 ∙ 𝑆𝑢
	 * Unidad		: KWh/a;
	 */
	private float GananciaInterna(){
		float gananciaInterna = 0;
		
		gananciaInterna = obtenerParametro(EnumParametros.QI)*edificioParaCalculo.getSuperficieUtil();
		
		return gananciaInterna;
	}

	//-----------------------------------------------------------------
	
	private float calcularRequerimientoTotalCalor(){
		float resp=0f;
		float fp_frio = obtenerParametro(EnumParametros.FPF);
		float fg_frio = obtenerParametro(EnumParametros.FGF);
		
		resp = fp_frio*( requerimiento.getPerdidasPorTransmision() + requerimiento.getPerdidasPorVentilacion() ) - 
			   fg_frio*( requerimiento.getGananciaTermicaSol() + requerimiento.getGananciaInterna());
		
		return resp;
	}
	
	private float calcularRequerimientoTotalFrio(){
		float resp = 0f;
		float fp_calor = obtenerParametro(EnumParametros.FPC);
		float fg_calor = obtenerParametro(EnumParametros.FGC);

		resp = fp_calor*( requerimiento.getPerdidasPorTransmision() + requerimiento.getPerdidasPorVentilacion() ) + 
		fg_calor*( requerimiento.getGananciaTermicaSol() + requerimiento.getGananciaInterna());
		
		return resp;
	}
	
	private float RequerimientoEnergeticoTotal(){
		
		if(edificioParaCalculo.getAireAcondicionado()==true)
			return (requerimiento.getRequerimientoCalorTotal() + requerimiento.getRequerimientoFrioTotal());
		
		return requerimiento.getRequerimientoCalorTotal();
	}
	
	/*
	 * Funciones utiles 
	 */
	private float areaTotalSecciones(){
		float resp = 0;
		
		for (SeccionTO seccionTO : seccionesEdificio) {
			
			resp += seccionTO.getArea();
		}
		
		return resp;
	}
	private float obtenerParametro(String parametro){
		float resp = -1;
		
			for (ParametrosEdificioTO p : parametrosEdificio) {
				if(p.getSimboloParametro().equals(parametro))
					resp = p.getValorParametro();
				
			}
		
		return resp;
	}
}
